/**
 *******************************************************************************
 * @file  usb/usb_dev_hid_custom/source/usb_bsp.c
 * @brief BSP function for USB example
 @verbatim
   Change Logs:
   Date             Author          Notes
   2020-06-12       CDT             First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include <stdio.h>
#include "usb_bsp.h"
#include "hc32_ddl.h"
#include "usb_dev_driver.h"
#include "usb_dev_custom_hid_class.h"

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
/* KEY10 */
#define KEY10_PORT      (GPIO_PORT_A)
#define KEY10_PIN       (GPIO_PIN_00)
#define KEY10_EXINT_CH  (EXINT_CH00)
#define KEY10_INT_SRC   (INT_PORT_EIRQ0)
#define KEY10_IRQn      (Int003_IRQn)

#ifdef USB_FS_MODE      /* USBFS Core*/
#define USB_DP_PORT     (GPIO_PORT_A)
#define USB_DP_PIN      (GPIO_PIN_12)
#define USB_DM_PORT     (GPIO_PORT_A)
#define USB_DM_PIN      (GPIO_PIN_11)
#define USB_VBUS_PORT   (GPIO_PORT_A)
#define USB_VBUS_PIN    (GPIO_PIN_09)
#define USB_SOF_PORT    (GPIO_PORT_A)
#define USB_SOF_PIN     (GPIO_PIN_08)
#else                   /* USBHS Core*/
#ifdef USB_HS_EXTERNAL_PHY
/* external PHY */
#define USBH_ULPI_CLK_PORT      (GPIO_PORT_E)
#define USBH_ULPI_CLK_PIN       (GPIO_PIN_12)
#define USBH_ULPI_DIR_PORT      (GPIO_PORT_C)
#define USBH_ULPI_DIR_PIN       (GPIO_PIN_02)
#define USBH_ULPI_NXT_PORT      (GPIO_PORT_C)
#define USBH_ULPI_NXT_PIN       (GPIO_PIN_03)
#define USBH_ULPI_STP_PORT      (GPIO_PORT_C)
#define USBH_ULPI_STP_PIN       (GPIO_PIN_00)
#define USBH_ULPI_D0_PORT       (GPIO_PORT_E)
#define USBH_ULPI_D0_PIN        (GPIO_PIN_13)
#define USBH_ULPI_D1_PORT       (GPIO_PORT_E)
#define USBH_ULPI_D1_PIN        (GPIO_PIN_14)
#define USBH_ULPI_D2_PORT       (GPIO_PORT_E)
#define USBH_ULPI_D2_PIN        (GPIO_PIN_15)
#define USBH_ULPI_D3_PORT       (GPIO_PORT_B)
#define USBH_ULPI_D3_PIN        (GPIO_PIN_10)
#define USBH_ULPI_D4_PORT       (GPIO_PORT_B)
#define USBH_ULPI_D4_PIN        (GPIO_PIN_11)
#define USBH_ULPI_D5_PORT       (GPIO_PORT_B)
#define USBH_ULPI_D5_PIN        (GPIO_PIN_12)
#define USBH_ULPI_D6_PORT       (GPIO_PORT_B)
#define USBH_ULPI_D6_PIN        (GPIO_PIN_13)
#define USBH_ULPI_D7_PORT       (GPIO_PORT_E)
#define USBH_ULPI_D7_PIN        (GPIO_PIN_11)
/* 3300 reset */
#define USB_3300_RESET_PORT     (EIO_PORT1)
#define USB_3300_RESET_PIN      (EIO_USB3300_RST)
#else
/* USBHS Core, embedded PHY */
#define USB_DP_PORT     (GPIO_PORT_B)
#define USB_DP_PIN      (GPIO_PIN_15)
#define USB_DM_PORT     (GPIO_PORT_B)
#define USB_DM_PIN      (GPIO_PIN_14)
#define USB_VBUS_PORT   (GPIO_PORT_B)
#define USB_VBUS_PIN    (GPIO_PIN_13)
#define USB_SOF_PORT    (GPIO_PORT_A)
#define USB_SOF_PIN     (GPIO_PIN_04)
#endif
#endif

#define TMR0x                   (M4_TMR0_1)
#define TMR0_CH_x               (TMR0_CH_A)
/* TMR0 interrupt source and number define */
#define TMR0_IRQn               (Int014_IRQn)
#define TMR0_SOURCE             (INT_TMR0_1_CMPA)

#define TMR0_CLK_SRC            (TMR0_CLK_SRC_LRC)
#define TMR0_CLK_DIV            (TMR0_CLK_DIV16)
#define TMR0_CMP_VAL            (32768UL/16UL)
/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
uint8_t PrevXferDone = 1U;

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
extern  usb_core_instance usb_dev;
extern  void hd_usb_isr_handler(usb_core_instance *pdev);

/**
 *******************************************************************************
 ** \brief  handle the USB interrupt
 ** \param  none
 ** \retval none
 ******************************************************************************/
static void USB_IRQ_Handler(void)
{
    hd_usb_isr_handler(&usb_dev);
}

///**
// *******************************************************************************
// ** \brief  KEY10 External interrupt Ch.0 callback function
// ** \brief  IRQ No.0 in Global IRQ entry No.0~31 is used for EXINT0
// ** \param  none
// ** \retval none
// ******************************************************************************/
//static void EXINT_KEY10_IrqCallback(void)
//{
//    if (Set == EXINT_GetExIntSrc(KEY10_EXINT_CH))
//    {
//        if ((PrevXferDone) && (usb_dev.dev.device_cur_status == USB_DEV_CONFIGURED))
//        {
//            Send_Buf[0U] = KEY_REPORT_ID;
//            if(Pin_Reset == GPIO_ReadInputPins(KEY10_PORT, KEY10_PIN))
//            {
//                Send_Buf[1] = 0x01U;
//            }
//            else
//            {
//                Send_Buf[1] = 0x00U;
//            }
//            hd_usb_deveptx(&usb_dev, HID_IN_EP, Send_Buf, 2);
//            PrevXferDone = 0U;
//        }
//        EXINT_ClrExIntSrc(KEY10_EXINT_CH);
//   }
//}

///**
// *******************************************************************************
// ** \brief  configure the gpio related with the KEY10 and the NVIC
// ** \param  none
// ** \retval none
// ******************************************************************************/
//static void Key10_Init(void)
//{
//    stc_exint_init_t stcExintInit;
//    stc_irq_signin_config_t stcIrqSignConfig;
//    stc_gpio_init_t stcGpioInit;

//    /* GPIO config */
//    GPIO_StructInit(&stcGpioInit);
//    stcGpioInit.u16ExInt = PIN_EXINT_ON;
//    stcGpioInit.u16PullUp = PIN_PU_ON;
//    GPIO_Init(KEY10_PORT, KEY10_PIN, &stcGpioInit);

//    /* Exint config */
//    EXINT_StructInit(&stcExintInit);
//    stcExintInit.u32ExIntCh = KEY10_EXINT_CH;
//    stcExintInit.u32ExIntLvl= EXINT_TRIGGER_FALLING;
//    EXINT_Init(&stcExintInit);

//    /* IRQ sign-in */
//    stcIrqSignConfig.enIntSrc = KEY10_INT_SRC;
//    stcIrqSignConfig.enIRQn   = KEY10_IRQn;
//    stcIrqSignConfig.pfnCallback = &EXINT_KEY10_IrqCallback;
//    INTC_IrqSignIn(&stcIrqSignConfig);

//    /* NVIC config */
//    NVIC_ClearPendingIRQ(KEY10_IRQn);
//    NVIC_SetPriority(KEY10_IRQn,DDL_IRQ_PRIORITY_DEFAULT);
//    NVIC_EnableIRQ(KEY10_IRQn);
//}

///**
// *******************************************************************************
// ** \brief  TMR0_1 channelA compare IRQ callback
// ** \param  none
// ** \retval none
// ******************************************************************************/
//static void TMR0_1_ChACmp_IrqCallback(void)
//{
//    if ((PrevXferDone) && (usb_dev.dev.device_cur_status == USB_DEV_CONFIGURED))
//    {
//        hd_usb_deveptx(&usb_dev, HID_IN_EP, NULL, 0);
//        PrevXferDone = 0U;
//    }
//    /* Clear the compare matching flag */
//    TMR0_ClearStatus(TMR0x, TMR0_CH_x);
//}

///**
// *******************************************************************************
// ** \brief  initialize the Timer0
// ** \param  none
// ** \retval none
// ******************************************************************************/
//static void TMR0_Init_1S(void)
//{
//    stc_tmr0_init_t stcTmr0Init;
//    stc_irq_signin_config_t stcIrqSignConfig;

//    /* Enable timer0 peripheral clock */
//    PWC_Fcg2PeriphClockCmd(PWC_FCG2_TMR0_1, Enable);

//    /* TIMER0 basetimer function initialize */
//    (void)TMR0_StructInit(&stcTmr0Init);
//    stcTmr0Init.u32ClockDivision = TMR0_CLK_DIV;        /* Config clock division */
//    stcTmr0Init.u32ClockSource = TMR0_CLK_SRC;          /* Chose clock source */
//    stcTmr0Init.u32Tmr0Func = TMR0_FUNC_CMP;            /* Timer0 compare mode */
//    stcTmr0Init.u32HwTrigFunc = TMR0_BT_HWTRG_FUNC_STOP;/* Config Hardware trigger function */
//    stcTmr0Init.u16CmpValue = TMR0_CMP_VAL;             /* Set compara register data */
//    (void)TMR0_Init(TMR0x, TMR0_CH_x, &stcTmr0Init);
//    /* In asynchronous clock, If you want to write a TMR0 register, you need to wait for at
//       least 3 asynchronous clock cycles after the last write operation! */
//    DDL_DelayMS(1U); /* Wait at least 3 asynchronous clock cycles.*/
//    /* Timer0 interrupt function Enable */
//    TMR0_IntCmd(TMR0x, TMR0_CH_x, Enable);
//    DDL_DelayMS(1U); /* Wait at least 3 asynchronous clock cycles.*/

//    /* Register IRQ handler && configure NVIC. */
//    stcIrqSignConfig.enIRQn = TMR0_IRQn;
//    stcIrqSignConfig.enIntSrc = TMR0_SOURCE;
//    stcIrqSignConfig.pfnCallback = &TMR0_1_ChACmp_IrqCallback;
//    (void)INTC_IrqSignIn(&stcIrqSignConfig);
//    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
//    NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIORITY_15);
//    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);

//    /* Timer0 ch1 start counting */
//    TMR0_Cmd(TMR0x, TMR0_CH_x, Enable);
//}

/**
 *******************************************************************************
 ** \brief  MCU Peripheral registers write unprotected.
 ** \param  none
 ** \retval none
 ** \note   Comment/uncomment each API depending on APP requires.
 ******************************************************************************/
static void Peripheral_WE(void)
{
    /* Unlock GPIO register: PSPCR, PCCR, PINAER, PCRxy, PFSRxy */
    GPIO_Unlock();
    /* Unlock PWC register: FCG0 */
    PWC_FCG0_Unlock();
    /* Unlock PWC, CLK, PVD registers, @ref PWC_REG_Write_Unlock_Code for details */
    PWC_Unlock(PWC_UNLOCK_CODE_0 | PWC_UNLOCK_CODE_1 | PWC_UNLOCK_CODE_2);
    /* Unlock SRAM register: WTCR */
    SRAM_WTCR_Unlock();
    /* Unlock SRAM register: CKCR */
    //SRAM_CKCR_Unlock();
    /* Unlock all EFM registers */
    EFM_Unlock();
    /* Unlock EFM register: FWMC */
    //EFM_FWMC_Unlock();
    /* Unlock EFM OTP write protect registers */
    //EFM_OTP_WP_Unlock();
}

/**
 *******************************************************************************
 ** \brief  MCU Peripheral registers write protected.
 ** \param  none
 ** \retval none
 ** \note   Comment/uncomment each API depending on APP requires.
 ******************************************************************************/
static __attribute__((unused)) void Peripheral_WP(void)
{
    /* Lock GPIO register: PSPCR, PCCR, PINAER, PCRxy, PFSRxy */
    GPIO_Lock();
    /* Lock PWC register: FCG0 */
    PWC_FCG0_Lock();
    /* Lock PWC, CLK, PVD registers, @ref PWC_REG_Write_Unlock_Code for details */
    PWC_Lock(PWC_UNLOCK_CODE_0 | PWC_UNLOCK_CODE_1 | PWC_UNLOCK_CODE_2);
    /* Lock SRAM register: WTCR */
    SRAM_WTCR_Lock();
    /* Lock SRAM register: CKCR */
    //SRAM_CKCR_Lock();
    /* Lock EFM OTP write protect registers */
    //EFM_OTP_WP_Lock();
    /* Lock EFM register: FWMC */
    //EFM_FWMC_Lock();
    /* Lock all EFM registers */
    EFM_Lock();
}

/**
 *******************************************************************************
 ** \brief  initialize configurations for the BSP
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void hd_usb_bsp_init(usb_core_instance *pdev)
{
    stc_gpio_init_t stcGpioCfg;

    Peripheral_WE();

//    BSP_CLK_Init();
//    BSP_IO_Init();
//    BSP_LED_Init();

//#if (DDL_PRINT_ENABLE == DDL_ON)
//    DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_PortInit);
//#endif
    /* USB clock source configurate */
    CLK_USB_ClkConfig(CLK_USB_CLK_MCLK_DIV5);

#if (DDL_PRINT_ENABLE == DDL_ON)
    DDL_Printf("USBFS start !!\r\n");
#endif
    GPIO_StructInit(&stcGpioCfg);
#ifdef USB_FS_MODE    
    stcGpioCfg.u16PinAttr = PIN_ATTR_ANALOG;
    GPIO_Init(USB_DM_PORT, USB_DM_PIN, &stcGpioCfg);
    GPIO_Init(USB_DP_PORT, USB_DP_PIN, &stcGpioCfg);
    GPIO_SetFunc(USB_VBUS_PORT, USB_VBUS_PIN, GPIO_FUNC_10_USBF_VBUS, PIN_SUBFUNC_DISABLE); //VBUS
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_USBFS, Enable);
#else

#ifdef USB_HS_EXTERNAL_PHY    //USBHS work in external PHY
    /* Reset 3300 */
    BSP_IO_WritePortPin(USB_3300_RESET_PORT, USB_3300_RESET_PIN, EIO_PIN_SET);
    BSP_IO_ConfigPortPin(USB_3300_RESET_PORT, USB_3300_RESET_PIN, EIO_DIR_OUT);

    GPIO_StructInit(&stcGpioCfg);
    /* High drive capability */
    stcGpioCfg.u16PinDrv = PIN_DRV_HIGH;
    GPIO_Init(USBH_ULPI_D0_PORT, USBH_ULPI_D0_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D1_PORT, USBH_ULPI_D1_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D2_PORT, USBH_ULPI_D2_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D3_PORT, USBH_ULPI_D3_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D4_PORT, USBH_ULPI_D4_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D5_PORT, USBH_ULPI_D5_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D6_PORT, USBH_ULPI_D6_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_D7_PORT, USBH_ULPI_D7_PIN, &stcGpioCfg);
    GPIO_Init(USBH_ULPI_STP_PORT, USBH_ULPI_STP_PIN, &stcGpioCfg);

    GPIO_SetFunc(USBH_ULPI_CLK_PORT, USBH_ULPI_CLK_PIN, GPIO_FUNC_10_USBH_ULPI_CK, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_DIR_PORT, USBH_ULPI_DIR_PIN, GPIO_FUNC_10_USBH_ULPI_DIR, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_NXT_PORT, USBH_ULPI_NXT_PIN, GPIO_FUNC_10_USBH_ULPI_NXT, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_STP_PORT, USBH_ULPI_STP_PIN, GPIO_FUNC_10_USBH_ULPI_STP, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D0_PORT, USBH_ULPI_D0_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D1_PORT, USBH_ULPI_D1_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D2_PORT, USBH_ULPI_D2_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D3_PORT, USBH_ULPI_D3_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D4_PORT, USBH_ULPI_D4_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D5_PORT, USBH_ULPI_D5_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D6_PORT, USBH_ULPI_D6_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);
    GPIO_SetFunc(USBH_ULPI_D7_PORT, USBH_ULPI_D7_PIN, GPIO_FUNC_10_USBH_ULPI_DATA, PIN_SUBFUNC_DISABLE);

    BSP_IO_WritePortPin(USB_3300_RESET_PORT, USB_3300_RESET_PIN, EIO_PIN_RESET);
#else                         //USBHS work in embedded PHY
    stcGpioCfg.u16PinAttr = PIN_ATTR_ANALOG;
    GPIO_Init(USB_DM_PORT, USB_DM_PIN, &stcGpioCfg);
    GPIO_Init(USB_DP_PORT, USB_DP_PIN, &stcGpioCfg);
    GPIO_SetFunc(USB_VBUS_PORT, USB_VBUS_PIN, GPIO_FUNC_12_USBH_VBUS, PIN_SUBFUNC_DISABLE);
#endif
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_USBHS, Enable);
#endif
}

/**
 *******************************************************************************
 ** \brief  configure the NVIC of USB
 ** \param  none
 ** \retval none
 ******************************************************************************/
void hd_usb_bsp_nvicconfig(void)
{
    stc_irq_signin_config_t stcIrqRegiConf;
    /* Register INT_USBFS_GLB Int to Vect.No.030 */
    stcIrqRegiConf.enIRQn = Int030_IRQn;
    /* Select interrupt function */
#ifdef USB_FS_MODE
    stcIrqRegiConf.enIntSrc = INT_USBFS_GLB;
#else
    stcIrqRegiConf.enIntSrc = INT_USBHS_GLB;
#endif
    /* Callback function */
    stcIrqRegiConf.pfnCallback = &USB_IRQ_Handler;
    /* Registration IRQ */
    INTC_IrqSignIn(&stcIrqRegiConf);
    /* Clear Pending */
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    /* Set priority */
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_15);
    /* Enable NVIC */
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}

/**
 *******************************************************************************
 ** \brief  This function provides delay time in micro sec
 ** \param  usec : Value of delay required in micro sec
 ** \retval None
 ******************************************************************************/
void hd_usb_udelay(const uint32_t usec)
{
    volatile uint32_t    i;
    uint32_t    j;
    j = HCLK_VALUE / 1000000UL * usec;
    for(i = 0UL; i < j; i++)
    {
        ;
    }
}

/**
 *******************************************************************************
 ** \brief  This function provides delay time in milli sec
 ** \param  msec : Value of delay required in milli sec
 ** \retval None
 ******************************************************************************/
void hd_usb_mdelay(const uint32_t msec)
{
    hd_usb_udelay(msec * 1000UL);
}

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
